﻿using System.Linq;
#if NETFX_CORE
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#else
using System.Windows;
using System.Windows.Controls;
#endif

namespace FreshMeat.Xaml
{
   /// <summary>
   /// Provides a cross-platform solution to something similar to WPF's DataTemplateSelector.
   /// Although Silverlight 5 now provides implicit data templates (as does WPF), the syntax
   /// for setting the DataType is different (WPF uses "{x:Type MyType} while Silverlight uses
   /// "MyType").  This class provides an alternative approach that works for both.
   /// </summary>
   public class DataTemplateSelector : ContentControl
   {
      /// <summary>
      /// Determines how to determine the value of the key which is used to choose from the available date templates.
      /// When null, the content's type name is used as the key; if no match is found, the search continues with the
      /// class names going up the inheritance chain and then through the names of all implemented interfaces 
      /// until a match is found.
      /// </summary>
      public readonly static DependencyProperty KeyProperty = DependencyProperty.Register(
         "Key",
         typeof(object),
         typeof(DataTemplateSelector),
         new PropertyMetadata(null, (o, args) => ((DataTemplateSelector)o).KeyChanged()));

      public DataTemplateSelector()
      {
         // These have different default values between WPF and Silverlight so set them to a known value here.
         HorizontalContentAlignment = HorizontalAlignment.Stretch;
         VerticalContentAlignment = VerticalAlignment.Stretch;
      }

      public override void OnApplyTemplate()
      {
         UpdateTemplate();

         base.OnApplyTemplate();
      }

      protected override void OnContentChanged(object oldContent, object newContent)
      {
         UpdateTemplate();

         base.OnContentChanged(oldContent, newContent);
      }

      void KeyChanged()
      {
         UpdateTemplate();
      }

      void UpdateTemplate()
      {
         var template = GetTemplate();
         //if (template != null)
         ContentTemplate = template;
      }
      
      DataTemplate GetTemplate()
      {
         if (Content == null)
            return null;

         if (Key == null)
         {
            // First look for a match starting with the content type's class
            // and going up through the class hierarchy.
            var type = Content.GetType();
            while (type != null)
            {
               var name = type.Name;
               if (Resources.Contains(name))
               {
                  var template = Resources[name] as DataTemplate;
                  return template;
               }

               type = type.BaseType;
            }

            // Next look for a match on any of the interfaces implemented by the content type.
            return (Content.GetType().GetInterfaces().Where(i => Resources.Contains(i.Name)).Select(i => Resources[i.Name] as DataTemplate)).FirstOrDefault();
         }

         var keyText = Key.ToString();
         if (Resources.Contains(keyText))
            return Resources[keyText] as DataTemplate;
         return null;
      }

      public object Key
      {
         get { return GetValue(KeyProperty); }
         set { SetValue(KeyProperty, value); }
      }
   }
}
